<?php

abstract class Workset_Model_Object_Iterator_Abstract implements Iterator, Countable {
	
	protected $_data = array();

    protected $_formatData = null;
	
	protected $_objects = array();
	
	protected $_pointer = 0;
	
	protected $_count = 0;
	
	protected $_objectClass = 'ArrayObject';

	protected $_objectOptions = null;

    protected $_keyIndex = null;

    protected $_keyPrefix = '';

    protected $_options = array();

    protected $_totalCount = 0;
	
	function __construct($data) {
		if (is_array($data) || $data instanceof ArrayAccess) {
			$this->_data = $data;
			$this->_count();		
		} else {
			throw new Workset_Model_Exception('Invalid data type in '.get_class($this));	
		}
	}

    function getNewInstance() {
        return clone $this;
    }
	
	function setObjectClass($class) {
		$this->_objectClass = $class;	
		return $this;
	}

	function setObjectOptions(array $options) {
		$this->_objectOptions = $options;
		return $this;
	}

    function setKeyIndex($key, $prefix = null) {
        $this->_keyIndex = $key;

        if (null !== $prefix) {
            $this->_keyPrefix = (string)$prefix;
        }

        return $this;
    }

    function setOptions($options) {
        $this->_options = array_merge($this->_options, $options);
        return $this;
    }

    function setTotalCount($total) {
        $this->_totalCount = (int)$total;
        return $this;
    }

    function getTotalCount() {
        return $this->_totalCount;
    }

	function current() {
		if ($this->_count === 0) {
            return null;
        }

		if (empty($this->_objects[$this->_pointer])) {
			$this->_objects[$this->_pointer] = new $this->_objectClass(
				$this->_data[$this->_pointer]
			);

			if (null !== $this->_objectOptions) {
				$this->_objects[$this->_pointer]->setOptions($this->_objectOptions);
			}
		}

		return $this->_objects[$this->_pointer];
	}
	
	function key() {
        if (null !== $this->_keyIndex) {
            if (is_array($this->_keyIndex)) {

                return implode($this->_keyPrefix, $this->_getArrayPart($this->_data[$this->_pointer], $this->_keyIndex));
                
            } elseif (isset($this->_data[$this->_pointer][$this->_keyIndex])) {
                
                return $this->_data[$this->_pointer][$this->_keyIndex];
            }
        }
        return $this->_pointer;
    }
    
    function next() {
        $this->_pointer++;
    }
    
    function valid() {
        return $this->_pointer < $this->_count;
    }
    
    function rewind() {
        $this->_pointer = 0;
        return $this;
    }
    
    function count() {
        return $this->_count;
    }

    function getIndex() {
        return $this->_pointer;
    }

    function toArray($keyIndex = null) {
        $result = array();
        foreach ($this as $key => $value) {
           if (null !== $keyIndex) {
               if (is_array($keyIndex)) {
                   $value = $this->_getArrayPart($value, $keyIndex);
               } else {
                   $value = $value[$keyIndex];
                   if (isInt($value)) {
                       $value = (int) $value;
                   }
               }
           }

           $result[$key] = $value;
        }
        return $result;
    } 

    protected function _getArrayPart($array, array $keys) {
        if (!is_array($array)) {
            if ($array instanceof Workset_Model_Object_Abstract) {
                $array = $array->toArray();
            } else {
                throw new Zend_Exception('Invalid argument type');
            }
        }

        //возвращаем значения выбранных значений массива в том порядке,
        //в котором перечислены ключи $keys
        $keys = array_flip($keys);
        $array = array_intersect_key($array, $keys);

        return array_values(array_merge($keys, $array));

    }

	function getData() {
		return $this->_data;
	}

    function remove($objects) {
        $listId = array();

        if (!$objects instanceof Iterator && !is_array($objects)) {
           $objects = array($objects);
        }

        foreach ($objects as $object) {
            if ($object instanceof $this->_objectClass) {
               $listId[] = $object->getId();
            } elseif ($object > 0) {
               $listId[] = (int)$object;
            }
        }

        foreach ($this as $object) {
            if (in_array($object->getId(), $listId)) {
                $this->_remove($this->getIndex());
            }
        }

        return $this;
    }

    function add($objects) {
        if (!$objects instanceof Iterator && !is_array($objects)) {
           $objects = array($objects);
        }

        foreach ($objects as $object) {
            if (!$object instanceof $this->_objectClass) {
               $object = call_user_func(array($this->_objectClass, 'getInstance'), $object);
            }
            $this->_add($object);
        }

        return $this;
    }

    function __clone() {
        if (is_object($this->_data)) {
            $this->_data = clone $this->_data;
        }
    }

    protected function _count() {
        if ($this->_data instanceof Countable) {
            $this->_count = $this->_data->count();
        } else {
            $this->_count = count($this->_data);
        }
    }

    protected function _add($object) {
        $this->_objects[$this->_count++] = $object;
    }

    protected function _remove($offset) {
        if (isset($this->_data[$offset])) {
            unset($this->_data[$offset]);

            if (isset($this->_objects[$offset])) {
                unset($this->_objects[$offset]);
            }

            $this->_count();
        }
    }



}

?>